﻿/**
 * @file aac_encoder_test.cpp
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-02-23
 * @version : 1.0.0.0
 * @brief   : PCM 音频数据编码（测试 aac_encoder_t）。
 */

#include "audio_aac.h"
#include "fwave_pcm.h"

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif // _MSC_VER

#include <vector>
#include <stdio.h>
#include <errno.h>

////////////////////////////////////////////////////////////////////////////////

/**
 * @brief 所支持全部的音频采样率（0 值表示保留值）。
 */
const x_uint32_t xut_samprate[16] =
{
    96000, 88200, 64000, 48000,
    44100, 32000, 24000, 22050,
    16000, 12000, 11025,  8000,
    7350, 0, 0, 0
};

/**********************************************************/
/**
 * @brief 返回音频采样率值对应的索引号（返回 -1 时，表示采样率值无效）。
 */
inline x_int32_t adts_samprate_index(x_uint32_t xut_samprate)
{
    x_int32_t xit_index = -1;

    switch (xut_samprate)
    {
        case 96000 : xit_index = 0x00; break;
        case 88200 : xit_index = 0x01; break;
        case 64000 : xit_index = 0x02; break;
        case 48000 : xit_index = 0x03; break;
        case 44100 : xit_index = 0x04; break;
        case 32000 : xit_index = 0x05; break;
        case 24000 : xit_index = 0x06; break;
        case 22050 : xit_index = 0x07; break;
        case 16000 : xit_index = 0x08; break;
        case 12000 : xit_index = 0x09; break;
        case 11025 : xit_index = 0x0A; break;
        case  8000 : xit_index = 0x0B; break;
        case  7350 : xit_index = 0x0C; break;

        default: break;
    }

    return xit_index;
}

/**********************************************************/
/**
 * @brief 填充 ADTS 头信息。
 * 
 * @param [out] xbuf_adts    : 要填充操作的 ADTS 缓存。
 * @param [in ] xut_len      : ADTS 帧数据长度（不包括 ADTS 头）。
 * @param [in ] xut_samprate : 音频采样率。
 * @param [in ] xut_channels : 音频通道数。
 * @param [in ] xut_aot      : 音频格式类型。
 * 
 */
x_void_t adts_fixed_head(
                x_byte_t   xbuf_adts[7],
                x_uint32_t xut_len,
                x_uint32_t xut_samprate,
                x_uint32_t xut_channels,
                x_uint32_t xut_aot)
{
    x_int32_t xit_index = adts_samprate_index(xut_samprate);

    xut_len += 7;

    xbuf_adts[0]  = 0xFF;                                // syncword : 0xFFF                       [H] 8 bits
    xbuf_adts[1]  = 0xF0;                                // syncword : 0xFFF                       [L] 4 bits
    xbuf_adts[1] |= (0 << 3);                            // MPEG Version : 0 for MPEG-4, 1 for MPEG-2  1 bit
    xbuf_adts[1] |= (0 << 1);                            // Layer : 0                                  2 bits
    xbuf_adts[1] |= 1;                                   // protection absent : 1                      1 bit
    xbuf_adts[2]  = (xut_aot - 1) << 6;                  // profile : xut_aot - 1                      2 bits
    xbuf_adts[2] |= (xit_index & 0x0F) << 2;             // sampling frequency index : xit_index       4 bits
    xbuf_adts[2] |= (0 << 1);                            // private bit : 0                            1 bit
    xbuf_adts[2] |= (xut_channels & 0x04) >> 2;          // channel configuration : xut_channels   [H] 1 bit
    xbuf_adts[3]  = (xut_channels & 0x03) << 6;          // channel configuration : xut_channels   [L] 2 bits
    xbuf_adts[3] |= (0 << 5);                            // original : 0                               1 bit
    xbuf_adts[3] |= (0 << 4);                            // home : 0                                   1 bit
    xbuf_adts[3] |= (0 << 3);                            // copyright id bit : 0                       1 bit
    xbuf_adts[3] |= (0 << 2);                            // copyright id start : 0                     1 bit
    xbuf_adts[3] |= ((xut_len & 0x1800) >> 11);          // frame length : xut_len                 [H] 2 bits
    xbuf_adts[4]  = (x_uint8_t)((xut_len & 0x7F8) >> 3); // frame length : xut_len                 [M] 8 bits
    xbuf_adts[5]  = (x_uint8_t)((xut_len & 0x7) << 5);   // frame length : xut_len                 [L] 3 bits
    xbuf_adts[5] |= 0x1F;                                // buffer fullness : 0x7FF                [H] 5 bits
    xbuf_adts[6]  = 0xFC;
}

////////////////////////////////////////////////////////////////////////////////

int main(int argc, char * argv[])
{
    x_errno_t xerr_no = X_ERR_UNKNOW;

    //======================================

    if (argc < 3)
    {
        printf("Usage: \n\t %s < wave-pcm-s16 input file > < aac output file >\n", argv[0]);
        return -1;
    }

    //======================================

    fwave_rpcm_t fwave_rpcm;
    xerr_no = fwave_rpcm.open(argv[1]);
    if (XERR_FAILED(xerr_no))
    {
        printf("fwave_rpcm.open([%s]) return error code: %s\n",
               argv[1], fwave_rpcm_t::xerrno_name(xerr_no));
        return -1;
    }

    if (16 != fwave_rpcm.format().xut_sampbits)
    {
        printf("(16 != fwave_rpcm.format().xut_sampbits[%d])\n",
               fwave_rpcm.format().xut_sampbits);
        return -1;
    }

    //======================================

    x_uint32_t xut_enconfig = XAAC_ENC_DEFAULT;
    x_uint32_t xut_bitrate  = 0;

    // XAAC_ENC_SET_AOT(xut_enconfig, XAAC_ENC_AOT_AAC_HE_V2);
    // XAAC_ENC_SETTMUX(xut_enconfig, XAAC_ENC_TMUXMP4_ADIF);

    aac_encoder_t aac_encoder;
    xerr_no = aac_encoder.open(
                    fwave_rpcm.format().xut_channels,
                    fwave_rpcm.format().xut_samprate,
                    xut_enconfig,
                    xut_bitrate);
    if (XERR_FAILED(xerr_no))
    {
        printf("aac_encoder.open(%d, %d, ...) return error code: %s\n",
               fwave_rpcm.format().xut_channels,
               fwave_rpcm.format().xut_samprate,
               aac_encoder_t::xerrno_name(xerr_no));
        return -1;
    }

    //======================================

    FILE * faac_writer = fopen(argv[2], "wb+");
    if (X_NULL == faac_writer)
    {
        printf("fopen([%s], \"wb+\") return X_NULL, errno: %d\n", argv[2], errno);
        return -1;
    }

    //======================================

    x_uint32_t xut_ibytes = aac_encoder.frame_len();
    x_uint32_t xut_obytes = aac_encoder.frame_len();

    std::vector< x_byte_t > xvec_input (xut_ibytes, 0);
    std::vector< x_byte_t > xvec_output(xut_obytes, 0);

    //======================================
    // AAC stream

    while (!fwave_rpcm.is_eof())
    {
        xut_ibytes = (x_uint32_t)fwave_rpcm.read(
                        xvec_input.data(), (x_fsize_t)xvec_input.size());
        if (xut_ibytes <= 0)
        {
            break;
        }

        if (xut_ibytes < aac_encoder.frame_len())
        {
            memset(xvec_input.data() + xut_ibytes, 0,
                   aac_encoder.frame_len() - xut_ibytes);
            xut_ibytes = aac_encoder.frame_len();
        }

        xut_obytes = (x_uint32_t)xvec_output.size();
        xerr_no = aac_encoder.encode(
                        xvec_output.data(),
                        xut_obytes,
                        (aac_encoder_t::cpcmbuf_t)xvec_input.data());
        if (XERR_FAILED(xerr_no))
        {
            printf("aac_encoder.encode(, %d, ) return error code: %s\n",
                    xut_obytes,
                    aac_encoder_t::xerrno_name(xerr_no));
            break;
        }

        printf("aac stream: input[%d], output[%d]\n", xut_ibytes, xut_obytes);
        if (xut_obytes <= 0)
        {
            continue;
        }

        fwrite(xvec_output.data(), sizeof(x_byte_t), xut_obytes, faac_writer);
    }

    //======================================

    if (X_NULL != faac_writer)
    {
        fclose(faac_writer);
        faac_writer = X_NULL;
    }

    fwave_rpcm.close();
    aac_encoder.close();

    //======================================

    return 0;
}
